﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace TXTD.Admin.Framework.ExpressionCore
{
    /// <summary>
    /// 表达式目录树 拼接查询条件
    /// </summary>
    public class ExpressionHelper<T>
    {
        private ParameterExpression parameter;
        private Expression _expression = null;
        public ExpressionHelper()
        {
            parameter = Expression.Parameter(typeof(T), "t");
        }
        #region 查询分类
        /// <summary>
        /// 等于 ==
        /// </summary>
        /// <param name="PropertyName">属性名称</param>
        /// <param name="searchValue">查询的值</param>
        /// <param name="addType">拼接类型</param>
        public void Eq(string PropertyName, object searchValue, ExpressionAddType addType = ExpressionAddType.And)
        {
            if (checkSearchValue(searchValue, out ConstantExpression constantExpression))
                Add(Expression.Equal(Expression.Property(parameter, PropertyName), constantExpression), addType);
        }
        /// <summary>
        /// 不等于 !=
        /// </summary>
        /// <param name="PropertyName"></param>
        /// <param name="searchValue"></param>
        /// <param name="addType"></param>
        public void NotEq(string PropertyName, object searchValue, ExpressionAddType addType = ExpressionAddType.And)
        {
            if (checkSearchValue(searchValue, out ConstantExpression constantExpression))
                Add(Expression.NotEqual(Expression.Property(parameter, PropertyName), constantExpression), addType);
        }
        /// <summary>
        /// 包含 like
        /// </summary>
        /// <param name="PropertyName"></param>
        /// <param name="searchValue"></param>
        /// <param name="addType"></param>
        public void Contains(string PropertyName, object searchValue, ExpressionAddType addType = ExpressionAddType.And)
        {
            if (checkSearchValue(searchValue, out ConstantExpression constantExpression))
            {
                MethodInfo? memberInfo = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
                if (memberInfo != null)
                {
                    Add(Expression.Call(Expression.Property(parameter, PropertyName), memberInfo, constantExpression), addType);
                }
            }
        }
        #endregion
        /// <summary>
        /// 验证查询值是否非空 非空的值才拼接条件
        /// </summary>
        /// <param name="searchValue"></param>
        /// <returns></returns>
        private bool checkSearchValue(object searchValue, out ConstantExpression constantExpression)
        {
            bool result = true;
            if (searchValue == null)
            {
                result = false;
            }
            //字符串
            if (result && searchValue is string)
            {
                searchValue = searchValue.ToString().Trim();
                if (searchValue == "")
                {
                    result = false;
                }
            }
            constantExpression = Expression.Constant(searchValue); ;
            return result;
        }
        /// <summary>
        /// 加入
        /// </summary>
        private void Add(Expression expression, ExpressionAddType addType)
        {
            if (_expression == null)
                _expression = expression;
            else
            {
                switch (addType)
                {
                    case ExpressionAddType.And:
                        _expression = Expression.And(_expression, expression);
                        break;
                    case ExpressionAddType.Or:
                        _expression = Expression.Or(_expression, expression);
                        break;
                }
            }
        }
        /// <summary>
        /// 获取拼接后的表达式目录树  
        /// </summary>
        /// <returns></returns>

        public Expression<Func<T, bool>> GetExpression()
        {
            if (_expression == null)
                return null;
            return Expression.Lambda<Func<T, bool>>(_expression, parameter);
        }
    }
}